﻿/*
 * BDictionary
 * 
 * Author: snowdreamist
 * Date: 2011/11/19
 * 
 */

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BitTorrentSharp.BEncoding
{
    public class BDictionary : BValue, IDictionary<BString, BValue>
    {
        /// <summary>
        /// internal dict
        /// </summary>
        private Dictionary<BString, BValue> _internalDict = new Dictionary<BString, BValue>();

        #region IDictionary

        public void Add(BString key, BValue value)
        {
            this._internalDict.Add(key, value);
        }

        public bool ContainsKey(BString key)
        {
            return this._internalDict.ContainsKey(key);
        }

        public ICollection<BString> Keys
        {
            get { return this._internalDict.Keys; }
        }

        public bool Remove(BString key)
        {
            return this._internalDict.Remove(key);
        }

        public bool TryGetValue(BString key, out BValue value)
        {
            return this._internalDict.TryGetValue(key, out value);
        }

        public ICollection<BValue> Values
        {
            get { return this._internalDict.Values; }
        }

        public BValue this[BString key]
        {
            get
            {
                return this._internalDict[key];
            }
            set
            {
                this._internalDict[key] = value;
            }
        }

        void ICollection<KeyValuePair<BString, BValue>>.Add(KeyValuePair<BString, BValue> item)
        {
            ((ICollection<KeyValuePair<BString, BValue>>)this._internalDict).Add(item);
        }

        public void Clear()
        {
            this._internalDict.Clear();
        }

        public bool Contains(KeyValuePair<BString, BValue> item)
        {
            return this._internalDict.Contains(item);
        }

        void ICollection<KeyValuePair<BString, BValue>>.CopyTo(KeyValuePair<BString, BValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return this._internalDict.Count; }
        }

        bool ICollection<KeyValuePair<BString, BValue>>.IsReadOnly
        {
            get { return ((ICollection<KeyValuePair<BString, BValue>>)this._internalDict).IsReadOnly; }
        }

        bool ICollection<KeyValuePair<BString, BValue>>.Remove(KeyValuePair<BString, BValue> item)
        {
            throw new NotImplementedException();
        }

        public IEnumerator<KeyValuePair<BString, BValue>> GetEnumerator()
        {
            return this._internalDict.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return ((System.Collections.IEnumerable)this._internalDict).GetEnumerator();
        }

        #endregion

        #region overrides

        internal protected override void InternalDeserialize(BinaryReader reader)
        {
            char topChar = (char)reader.PeekChar();
            if (topChar != 'd')
                throw new BEncodingException(string.Format("Not a dictionary, input {0}", topChar));

            this._internalDict.Clear();
            reader.ReadChar();

            while (reader.PeekChar() != 'e')
            {
                BValue key = BValue.Deserialize(reader);

                if (!(key is BString))
                    throw new BEncodingException(string.Format("Expect BString but {0}", key.GetType().Name));

                BValue value = BValue.Deserialize(reader);

                this._internalDict.Add(key as BString, value);
            }

            // current char is e, read it
            reader.ReadChar();
        }

        internal protected override void InternalSerialize(BinaryWriter writer)
        {
            writer.Write((byte)'d');
            this.SerializeContent(writer);
            writer.Write((byte)'e');
        }

        protected internal override void InternalSerializeContent(BinaryWriter writer)
        {
            var sortedDict = this._internalDict.OrderBy(p => p.Key);
            foreach (var item in sortedDict)
            {
                item.Key.Serialize(writer);
                item.Value.Serialize(writer);
            }
        }

        #endregion


    }
}
